# -*- coding:UTF-8 -*-

import rpyc
import json
import logging
import os
import re
import random
import requests
from logging.handlers import TimedRotatingFileHandler
from rpyc.utils.server import ThreadedServer
from rpyc import Service
# 阿里云生成域名相关SDK
from aliyunsdkcore.client import AcsClient
from aliyunsdkcore.acs_exception.exceptions import ClientException
from aliyunsdkcore.acs_exception.exceptions import ServerException
from aliyunsdkcore.auth.credentials import AccessKeyCredential
from aliyunsdkcore.auth.credentials import StsTokenCredential
from aliyunsdkalidns.request.v20150109.AddDomainRecordRequest import AddDomainRecordRequest
from aliyunsdkalidns.request.v20150109.DescribeSubDomainRecordsRequest import DescribeSubDomainRecordsRequest
from aliyunsdkalidns.request.v20150109.SetDomainRecordStatusRequest import SetDomainRecordStatusRequest
from aliyunsdkalidns.request.v20150109.UpdateDomainRecordRequest import UpdateDomainRecordRequest
from aliyunsdkalidns.request.v20150109.DeleteDomainRecordRequest import DeleteDomainRecordRequest

from config import RPCIP, RPCPORT, WRITE_IN_LOG

rpyc.core.protocol.DEFAULT_CONFIG['allow_pickle'] = True


# 日志按天分割，保存近一个月日志，日志自动清理
def setup_log(log_name):
    # 创建logger对象。传入logger名字
    logger = logging.getLogger(log_name)

    log_file = os.path.join(os.getcwd(), "log", log_name)
    # log_file = os.path.join(log_path, log_name)
    # if not os.path.exists(log_path):
    #     os.makedirs(log_path)

    # 设置日志记录等级
    logger.setLevel(logging.INFO)
    # interval 滚动周期，
    # when="MIDNIGHT", interval=1 表示每天0点为更新点，每天生成一个文件
    # backupCount  表示日志保存个数
    file_handler = TimedRotatingFileHandler(
        filename=log_file, when="MIDNIGHT", interval=1, backupCount=30)
    # filename="mylog" suffix设置，会生成文件名为mylog.2023-02-25.log
    file_handler.suffix = "%Y-%m-%d.log"
    # extMatch是编译好正则表达式，用于匹配日志文件名后缀
    # 需要注意的是suffix和extMatch一定要匹配的上，如果不匹配，过期日志不会被删除。
    file_handler.extMatch = re.compile(r"^\d{4}-\d{2}-\d{2}.log$")
    # 定义日志输出格式
    file_handler.setFormatter(
        logging.Formatter(
            "[%(asctime)s] [%(process)d] [%(levelname)s] - %(module)s.%(funcName)s (%(filename)s:%(lineno)d) - %(message)s"
        )
    )
    logger.addHandler(file_handler)
    return logger


def client_init():
    try:
        credentials = AccessKeyCredential(
            'LTAII5qYZbJpQQai', 'Xaw9Ges85fHh2jEioZU7IVbgV32MnU')
        # use STS Token
        # credentials = StsTokenCredential('<your-access-key-id>', '<your-access-key-secret>', '<your-sts-token>')
        client = AcsClient(region_id='cn-qingdao', credential=credentials)
    except Exception as _:
        return None
    return client


logger = setup_log("domainserver.log")


class AiApiDomainService(Service):
    # class AiApiDomainService():
    def exposed_add_domain(self, app_name, ip):
        r_str = random.sample('zyxwvutsrqponmlkjihgfedcba', 5)
        r_str = "".join(r_str)
        rr = f"{random.randint(0, 9)}-{random.randint(0, 9)}-{random.randint(0, 9)}-{random.randint(0, 9)}"
        rr = f"{rr}-{r_str}_{random.randint(0, 9)}"
        rr = f"{app_name}-{rr}"
        client = client_init()
        if client is None:
            return False, "域名服务连接异常", "", ""

        request = AddDomainRecordRequest()
        request.set_accept_format('json')

        request.set_DomainName("aiapi.pro")
        request.set_RR(rr)  # 子域名
        request.set_Type("A")
        request.set_Value(str(ip))  # 绑定的IP
        headers = {
            "Content-type": "application/json"
        }
        try:
            response = client.do_action_with_exception(request)
            response = json.loads(str(response, encoding='utf-8'))
            RecordId = response['RecordId']
            data = {
                "domain_record_id": RecordId,
                "domain_type": "A",
                "domain": f"{rr}.aiapi.pro",
                "ip": str(ip)
            }
            response = requests.post(
                WRITE_IN_LOG, json=data, headers=headers, verify=False, timeout=10)
            if response.status_code != 200:
                return False, "域名服务连接出错", "", ""

            return True, "ok", response.json()['id'], f"{rr}.aiapi.pro"
        except Exception as e:
            return False, f"{e}", "", ""

    def exposed_search_sub_domain(self, rr):
        sub_domain = str(rr)
        client = client_init()
        if client is None:
            return False, "域名服务连接异常", "", ""
        request = DescribeSubDomainRecordsRequest()
        request.set_accept_format('json')
        rr = f"{str(rr)}.aiapi.pro"

        request.set_SubDomain(str(rr))
        request.set_DomainName("aiapi.pro")
        request.set_Type("A")

        response = client.do_action_with_exception(request)
        response = json.loads(str(response, encoding='utf-8'))
        RequestId = response.get("RequestId", None)
        RecordId = ""
        status = ""
        if RequestId is None:
            return False, "", RecordId, status

        for Record in response.get("DomainRecords", {}).get("Record", []):
            if Record['RR'] == sub_domain:
                RecordId = Record['RecordId']
                status = Record['Status']

        if RecordId == "":
            return False, "", RecordId, status

        return True, RequestId, RecordId, status

    def exposed_set_domain_status(self, RecordId, status=False):
        RecordId = str(RecordId)

        client = client_init()
        if client is None:
            return False, "域名服务连接异常", ""
        request = SetDomainRecordStatusRequest()
        request.set_accept_format('json')

        request.set_RecordId(RecordId)
        _status = "Disable"
        if status:
            _status = "Enable"
        request.set_Status(_status)

        try:
            response = client.do_action_with_exception(request)
            response = json.loads(str(response, encoding='utf-8'))
            return True, response['RecordId'], response['Status']
        except Exception as e:
            return False, f"{e}", f"{e}"

    def exposed_update_domain(self, RecordId, rr, ip):
        client = client_init()
        if client is None:
            return False, "域名服务连接异常"
        request = UpdateDomainRecordRequest()
        request.set_accept_format('json')
        request.set_RecordId(str(RecordId))
        request.set_RR(str(rr))
        request.set_Type("A")
        request.set_Value(str(ip))
        try:
            response = client.do_action_with_exception(request)
            response = json.loads(str(response, encoding='utf-8'))
            return True, response['RecordId']
        except Exception as e:
            return False, f"{e}"

    def exposed_del_domain(self, RecordId):
        client = client_init()
        if client is None:
            return False, "域名服务连接异常"
        request = DeleteDomainRecordRequest()
        request.set_accept_format('json')
        request.set_RecordId(str(RecordId))
        _ = client.do_action_with_exception(request)
        # python2:  print(response)
        return True, "ok"

    def exposed_test_connect(self):
        return


if __name__ == '__main__':
    # rpc服务

    print(f"--------------域名rpc服务以启动--------------ip={RPCIP},port={RPCPORT}")
    # 启动服务
    s = ThreadedServer(AiApiDomainService, hostname=RPCIP, port=RPCPORT,
                       protocol_config=rpyc.core.protocol.DEFAULT_CONFIG)
    s.start()
